#ifndef Archer_H_20120313
#define Archer_H_20120313

#include "cocos2d.h"
#include "SkeletalAnimation/SkinAnimation.h"
#include "Arrow.h"
#include "ArcherBase.h"
#include "Bow.h"
#include <list>

//  人物结构索引

// 弓箭手身体位置索引
enum ArcherIndex
{
    ARCHER_INDEX_BODY,
    ARCHER_INDEX_NECK,
    ARCHER_INDEX_HEAD ,
    ARCHER_INDEX_SHOULDER,
    ARCHER_INDEX_LEFTARMBONE,
    ARCHER_INDEX_LEFTARM,
    ARCHER_INDEX_RIGHTARMBONE,
    ARCHER_INDEX_RIGHTARM,
    ARCHER_INDEX_LEFTHANDBONE,
    ARCHER_INDEX_LEFTHAND,
    ARCHER_INDEX_RIGHTHANDBONE,
    ARCHER_INDEX_RIGHTHAND,
    ARCHER_INDEX_BOW,
    ARCHER_INDEX_ARROW,
    ARCHER_INDEX_MAX
};

// 每个部分的z序
enum ArcherZorder
{
    ARCHER_ZORDER_RIGHTHAND,
    ARCHER_ZORDER_RIGHTARM,
    ARCHER_ZORDER_BODY,
    ARCHER_ZORDER_LEFTARM,
    ARCHER_ZORDER_HEAD,
    ARCHER_ZORDER_LEFTHAND,
    ARCHER_ZORDER_BOW,
    ARCHER_ZORDER_ARROW
};

  

// 人物初始化信息
struct ArcherFrameInfo
{
	char             _szSpritePath[128];    // 图片路径
    bool             _bUseFrame;
	cocos2d::CCPoint _ptSize;               // 原始图片尺寸
	cocos2d::CCPoint _ptAnchor;             // 图片锚点
	cocos2d::CCPoint _ptAnchorParent;       // 父锚点
	cocos2d::CCPoint _ptPos;                // 在父中的位置
	float            _startRot;             // 初始
	float            _zOrder;               // z序
};

// 弓箭手一个部位的信息
struct ArcherImageData
{
    cocos2d::CCPoint _ptSize;       // 图片尺寸
    cocos2d::CCPoint _ptAnchor;     // 锚点
    cocos2d::CCPoint _ptPos;        // 在父中的位置
    bool             _bUseFrame;    // 是否使用缓存加载
    char             _name[32];     // 文件名
};

// 弓箭手初始化时传入的参数
struct ArcherInitData
{
    ArcherImageData _dataHead;      // 头
    ArcherImageData _dataBody;      // 身体
    ArcherImageData _dataArm;       // 手臂
    ArcherImageData _dataHand;      // 手
    ArcherImageData _dataBow;       // 弓箭
};

// 弓箭手动作信息
struct ArcherAnimInfo
{
    bool             _bUseLocalTime;        // 是否使用本地消息，如果启用，则更新时不根据传入的当前时间进行更新
    
    // 一般说，一个骨骼旋转和位移动作只有一个
	int              _posKeyCount;          // 位移键数量，如果没有位移动画，置0
	Vector3D         _posKeys[3];           // 位移（相对）
	float            _posTimes[3];          // 每一段位移对应的时间（0-1）
    
	int              _rotKeyCount;
	float            _rotKeys[3];
	float            _rotTimes[3];
    
    ArcherAnimInfo()
    {
        _bUseLocalTime = false;
        _posKeyCount   = 0;
        _rotKeyCount   = 0;
    }
};

struct AABBInfo
{
    AABB                 _aabbHead;       // AABB当前信息
    AABB                 _aabbBody;
    AABB                 _aabbFoot;
};

struct HurtInfo
{
    int              _type;
    int              _hp;
    cocos2d::CCPoint _ptPos;
    
    HurtInfo()
    {
        _type = -1;
        _hp   = 0;
    }
};


const float Archer_AUTOSHOOT_DELAY = 0.01f;
const float Archer_AUTOSHOOT_WAIT  = 1.0f;
class CArcher : public CSkeletalLayer, public CArcherBase
{
public:
    enum AutoShootStep
    {
        AUTO_STEP_NONE,
        AUTO_STEP_MOVE,
        AUTO_STEP_ROT,
        AUTO_STEP_POWER,
        AUTO_STEP_WAIT
    };
public:

    static CArcher *CreateArcher(int id, bool bFlip, cocos2d::CCNode *pParent, int zOrder, const BowInfo &initBow, const ArrowInfo &arrowInfo);
    LAYER_NODE_FUNC(CArcher);
    
	CArcher()
        : m_bValid(false)
		, m_pCurTouch(NULL)
        , m_pCurArrow(NULL)
        , m_autoStep(AUTO_STEP_NONE)
        , m_bUpdateBow(true)
        , m_bWalking(false)
        , m_pSprBlood(NULL)
        , m_bCanMove(true)
		, m_nSoundPreshoot(-1)
        
	{

	}
    
	bool  IsValid()                    const {return m_bValid;}
    bool  IsAutoShooting()             const {return (m_autoStep != AUTO_STEP_NONE);}
    bool  IsFlip()                     const {return m_bFlip;}
    bool  IsWalking()                  const {return m_bWalking;}
    bool  IsCanMove()                  const {return m_bCanMove;}
    
    cocos2d::CCPoint GetPos()          const {return ccp(m_ptPos.x, m_ptPos.y);}
    CArrow*          GetCurArrow()     const {return m_pCurArrow;}
    float            GetLastPower()    const {return m_lastPower;}
    const ArrowInfo& GetCurArrowInfo() const {return m_curArrowInfo;}
	int              GetID()           const {return m_id;}
    // 获取左手位置，用于更新弓弦
    cocos2d::CCPoint GetLeftHandPos();
    
    void SetValid(bool bValid)      {m_bValid = bValid;}
    void SetUpdateBow(bool bUpdate) {m_bUpdateBow = bUpdate;}
    // 设置是否翻转，设置生效后，骨骼和动画信息将会变化
    void SetFlip(bool bFlip);
    // 设置下一支射出的箭的参数
    void SetCurArrow(const ArrowInfo &info);
    // 设置发射角度，如果角色向右，角度范围为-90 —— 90 ，向左则90 —— （+-180） —— -90
	void SetCurRotate(float angle);
    
    void InitState(int id, int type, const ArcherInitData &d,bool bFlip, const BowInfo &bowInfo, const ArrowInfo &arrowInfo, const AABBInfo &aabbInfo);
    void Update(cocos2d::ccTime dt);
    
    // 移动，会根据方向进行翻转，并更新AABB信息
	void MoveLeft();
	void MoveRight();
    void MoveTo(cocos2d::CCPoint pt);
    // 如果正在移动，则将会从移动状态切换到射箭状态
    void MoveStop();
    
    
    // 增加目标
    void AddTarget(CArcherBase *pTarget);
    void AttachFrame(int parentIndex, cocos2d::CCPoint pt, float angle, cocos2d::CCSprite *pSpr = NULL);
    
    // 如果可以发射一支箭，则返回新实例，自身不管理
	CArrow *BeginTouches(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent);
	void    MoveTouches(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent);
	bool    DisableTouches(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent);
    // 自动射一直箭，可以用于AI或者网络对手, 在 UpdateAutoShoot中更新这支自动发射的箭
    CArrow *AutoShoot(float power, float angle, float xMove, float yMove, bool bFlip);
    // 没有更新完返回true 不需要更新返回false
    bool    UpdateAutoShoot(cocos2d::ccTime dt);
    // 再射手手上增加了一支箭，并返回这支箭的指针
    CArrow *AddArrow();
    // 为这支箭初始化参数，将这支箭取消与弓箭手的关联
    CArrow *Shoot(cocos2d::CCPoint ptHead, float angle, float power);
    void    Dead(int groundHeight);
    
    bool    Hurt(int hurtPos, const ArrowInfo &arrowInfo, cocos2d::CCSprite *pArrowFlying);
    // 检查受伤情况，根据受伤情况做相应动作
    bool    CheckHurt(const ArrowInfo &arrowInfo, cocos2d::CCSprite *pArrowFlying);
    
protected:
    
    // 设置当前力量，根据触摸点来计算去顶
	void SetCurStrength(float s);
    // 伤害动作结束后调用
    void OnHurtEnd();
    // 切换到射箭动画
    void SetPrepareShoot();
   
public:
    /**************继承父类**************/
    // 引发力量变化
	virtual void animationChange();
    // 被击中
    void Hitted(HitPositon pos, MyPoint ptHurt);
    // 设置人物位置，影响AABB
    void SetPos(const cocos2d::CCPoint &ptPos);
    
protected:
    /**************需要子类继承***********/
    // 初始化AABB，根据当前是否翻转,不同的造型有不同的AABB
    void _InitAABB(const AABBInfo &aabbInfo);
    // 初始化序列帧相关信息
    void _InitActions();
    void _FlipActions(bool bFlip);
    // 初始化弓箭信息
    void _InitBowInfo(const BowInfo &bowInfo);
    // 根据各个部分信息组建起骨骼
    void _BuildArcherFrame(const ArcherInitData &archerData);
    // 初始化骨骼信息
    void _InitFrames(ArcherFrameInfo frameInfo[ARCHER_INDEX_MAX], bool bFlip, bool bLoadTexture);
    // 增加一个新的动画
    void _AddAnimation(ArcherAnimInfo animInfo[ARCHER_INDEX_MAX], const char *szAnimName, float length);
    // 改变一个已有的动画
    void _ChangeAnimation(ArcherAnimInfo animInfo[ARCHER_INDEX_MAX], const char *szAnimName);
    // 设置动画，如果bFirst 则动画内容将被NEW，只有第一次创建时bFirst设置成true
    void _SetLocalAnimation(bool bFlip, bool bFirst = true);
    void _SetHurtAnimation(bool bFlip, bool bFirst = true);
    void _SetHurtBodyAnimation(bool bFlip, bool bFirst = true);
    void _SetWalkAnimation(bool bFlip, bool bFirst = true);
    
protected:
	void OnEffectPreShoot();
protected:
	CSpriteBow          *m_pSprBow;        // 当前角色正在使用的弓
	cocos2d::CCTouch    *m_pCurTouch;
    cocos2d::CCSprite   *m_pSprHurt;
    cocos2d::CCSprite   *m_pSprBlood;
    cocos2d::CCPoint     m_ptLeftHand;
    
	int                  m_id;
    int                  m_type;
	bool                 m_bValid;       // 是否可以射箭，影响TOUCH消息接收
    float                m_armLength;    // 手臂长度，用来计算动作信息
    bool                 m_bUpdateBow;   // 是否更新弓箭，如果不更新，则箭弦不跟随手移动
    bool                 m_bWalking;     // 是否正在行走
    bool                 m_bCanMove;
    
    CArrow              *m_pCurArrow;   // 当前正在射出的箭
    
    Frame               *m_apFrames[ARCHER_INDEX_MAX];   // 骨骼信息，用于建立动作时进行关联，再初始化骨架时赋值
    ArcherFrameInfo      m_frameInfo[ARCHER_INDEX_MAX]; // 骨架信息，用于来回翻转保存原始信息
    float                m_flipDiff;                     // 由于翻转时不根据锚点，因此翻转图片将会有一个X偏移
    float                m_lastPower;                    // 保存刚刚射出的箭所用的力量
    
    // 一下变量用于自动射箭
    AutoShootStep       m_autoStep;
    float               m_autoAngle;
    float               m_autoPower;
    int                 m_autoMoveX;
    int                 m_autoMoveY;
    bool                m_autoFlip;
    
    cocos2d::CCAction  *m_pActHurt;         // 动作
    cocos2d::CCAction  *m_pActBlood;    
    
    ArrowInfo           m_curArrowInfo;     // 保存当前箭矢信息，用来初始化箭矢
    HurtInfo            m_hurtInfo;         // 当角色判定受伤时，将受伤信息保存于此，需要检查时调用
    map<Frame *, int>   m_mapFrameAttached;
    
    int                 m_nSoundPreshoot;
    
};

typedef list<CArcher *> ArcherList;


class CArcherManager
{
public:
   
    static void     SetSceneInfo(cocos2d::CCNode *pParent, int zOrder);
    static CArcher *CreateArcher(int id, bool bLeft, int type, int bowID, int arrowID);
private:
    static cocos2d::CCNode *m_pParent;
    static int              m_archerOrder;
    
};


#endif